[CmdletBinding(DefaultParameterSetName='Single')]param(
    [Parameter(Mandatory=$true,Position=0,ParameterSetName='Single')]
    [ValidateScript({(test-path $_) -and [io.path]::GetExtension($_) -eq ".csv"})]
    [string]$old_csv,
    [Parameter(Mandatory=$true,Position=1,ParameterSetName='Single')]
    [ValidateScript({(test-path $_) -and [io.path]::GetExtension($_) -eq ".csv"})]
    [string]$new_csv,
    [Parameter(Mandatory=$false,ParameterSetName='All')]
    [switch]$AllNew
)
Function Write-Log(){
    [CmdletBinding()]param(
		[Parameter(Mandatory=$true)]
		[ValidateSet("Warning", "Error", "Success","Normal","Critical")]
		[string]$log_type,
		[string]$log_info,
		[string]$log_file="$home\Documents\WindowsPowerShell\log.txt",
        [Parameter(Mandatory=$false)]
        [switch]$print_to_console
	)
    If( $print_to_console ){
        $color = switch -regex ($log_type){
            "Error|Critical"  {'red';break }
            "Warning"{'yellow' ;break}
            "Success"{'green'  ;break}
            default {'white'}
        }
        write-host -fore $color $log_info
    }
	Do{
	    Try{"{0:yyyy-MM-dd HH:mm:ss}--{1}: {2}" -f (get-date),$log_type,$log_info |Out-File -FilePath $log_file -Append -Encoding utf8 -Force -ea 1;break}Catch{ write-host $_ ; read-host " ";sleep -Milliseconds 200 ;if(++$cnt -gt 10){write-error "wait too long(2s) to write log";break}
		}Finally{}
	}While(1)
}
Function New-Shortcut(){
    [CmdletBinding()]param(
        [Parameter(Mandatory=$True)]
        [string]$shortcut_path,
        [string]$target_path
    )
    $WshShell = New-Object -comObject WScript.Shell
    $shortcut = $WshShell.CreateShortcut($shortcut_path)
    $shortcut.TargetPath = $target_path
    $shortcut.Save()
}
Function Exit-Script($error_info,$log_file,$compare_path,[switch]$OpenFolder){
    If( ![string]::IsNullOrWhiteSpace($error_info ) ){
        write-log Error $error_info $log_file
    }
    write-host -fore yellow "The compare folder is --> '$compare_path'" ; exit
}
If( $AllNew){ #<--------------------------------------------------------------------# try to compare all the new collected csv files
    Foreach( $output_folder in (dir "$PSScriptRoot\output").fullname){              # get all the typs folders
        $latest_two_csv_file=(dir "$output_folder\*.csv"|sort LastWriteTime|select -Last 2).fullname # get the latest_two_csv_file in each folder
        If( $latest_two_csv_file.count -eq 2){                                      # if found latest 2 csv files, compare them
            write-host "Starting to compare csv files in $output_folder"
            powershell -file "$PSScriptRoot\compare.ps1" "$($latest_two_csv_file[0])" "$($latest_two_csv_file[1])"
        }else{
            write-host "Not found 2 csv files in $output_folder"
        }
    }
    #<------------------------------------------------------------------------------# popup message for notifying user of script completion
    (quser 2>$null) -imatch "active"|%{msg ($_ -split(">| +"))[1] /TIME:5 /V 'Compare Finished(this window will automatically disappear in 5s)' 1>$null 2>&1}
}else{
    #<------------------------------------------------------------------------------# initilize 2 csv file info
    $this_path=$PSScriptRoot ; $old_file_info=gi $old_csv ; $new_file_info=gi $new_csv
    $old_file_basename=$old_file_info.basename ; $new_file_basename=$new_file_info.basename
    If( $old_file_basename -imatch "(?<date>\d{8}_\d{6})+_(?<kind>.*)"){
        $old_file_basename="{0}_{1}" -f $Matches.kind,$Matches.date
        If( $new_file_info.Name -imatch "(?<date>\d{8}_\d{6})+"){
            $new_file_basename=$Matches.date
        }
    }
    $compare_path="$this_path\compare\$old_file_basename-$new_file_basename"        # the folder to store compare results
    if(!(test-path $compare_path -ea 4)){                                           # if the the compare folder
        new-item -ItemType Directory -path $compare_path -Force -ea 0|out-null      # not exists, create it
    }else{                                                                          # or if it already exist
        Exit-Script '' $log_file $compare_path                                      # then exit the script casue the 2 csvs have already been compared
    }
    $log_file = "$compare_path\out.log"                                             # log to store running info
    If( $old_file_info.Name -eq $new_file_info.Name ){                              # exit if they are the same file
        Exit-Script "The 2 compared csv files`r`n$old_csv`r`n$new_csv`r`nare the same!" $log_file $compare_path
    }
    Try{
        $old_csv=resolve-path $old_csv -ea 1; $new_csv=resolve-path $new_csv -ea 1
    }Catch{                                                                         # exit if file not exits
        Exit-Script $_.Exception.Message ("$this_path\{0}_error.log" -f (gi $PSCommandPath).BaseName ) $compare_path   
    }Finally{}
    #<------------------------------------------------------------------------------# load 2 csv content and the csv header
    $old_csv_content=(ipcsv $old_csv) ; $old_header=$old_csv_content[0].psobject.Properties | foreach { $_.Name }
    $new_csv_content=(ipcsv $new_csv) ; $new_header=$new_csv_content[0].psobject.Properties | foreach { $_.Name }
    If( $old_header.count -ne $new_header.count){                                   # exit if the 2 csv files header counts not equal
        Exit-Script "The 2 compared csv files`r`n$old_csv`r`n$new_csv`r`nhave different headers!" $log_file $compare_path 
    }else{
        For( $n=0; $n -lt $old_header.count; $n++ ){                                # exit if the 2 csv files header names not same
            If( $old_header[$n] -ne $new_header[$n] ){
                Exit-Script "The 2 compared csv files`r`n$old_csv`r`n$new_csv`r`nhave different headers or same header names but different header sequence!" $log_file $compare_path  
            }
        }
    }
    #<------------------------------------------------------------------------------------# create the shortcut for the original old and new csv
    New-Shortcut "$compare_path\old-$($old_file_info.basename).lnk" $old_csv ; New-Shortcut "$compare_path\new-$($new_file_info.basename).lnk" $new_csv 
    #<------------------------------------------------------------------------------------# start to compare the 2 csv content with formated column name
    if(($action_result=compare-object $old_csv_content $new_csv_content -Property $old_header|select (@(@{n="Action";e={if($_.SideIndicator -eq "=>"){"Grant"}else{"Revoke"}}})+$old_header)) -ne $null){                                   # about 40 secs for "role_access_to_folder" compare
        $compare_result_csv="$compare_path\$old_file_basename-$new_file_basename`.csv"    # the csv to store compare results
        $action_result|Export-Csv -Path $compare_result_csv -UseCulture -NoTypeInformation -Encoding UTF8 -Force -ea 1
        # write-host ("{0}-original report done" -f (Get-Date).ToString("MM/dd/yyyy HH:mm:ss"))
        If($old_csv -imatch "role_access_to_folder" -or ($old_header[0..2] -join "" -eq 'RoleAccessFolder')){ # if for role_access_to_folder compare
            If( ($dbenv=((gi $compare_result_csv).basename -split('_db'))[0])){                               # get compare report source db domain and env
                If( $parent_folder=((cat "$this_path\repository_list.txt") -imatch $dbenv).split('=')[-1] ){ # get $dbenv websocket server repository folder
                    $action_result_header=$action_result[0].psobject.Properties | foreach { $_.Name } # get $action_result header
                    $existence_result=$action_result|select ($action_result_header+@{n="Existence";e={if(test-path (Join-Path $parent_folder $_.Folder)){1}else{0}}}) # save the compare result for role_access_to_folder type with one more colunm "Existence"
                    $existence_result|Export-Csv -Path $compare_result_csv -UseCulture -NoTypeInformation -Encoding UTF8 -Force -ea 1
                }Else{
                    write-log Error "Unable to find $dbenv websocket server repository folder in '$this_path\repository_list.txt'" $log_file
                }
            }Else{
                write-log Error "Unable to tell which DB env this report data is from by it file name" $log_file
            }
            #<----------------------------------------------------------------------------# try to simplify role_access_to_folder compare data
            If( $ei=cat "$this_path\exclude_items.txt" -ea 0 ){                           # get exclude items(ei)
                $er=($ei -imatch 'exclude_role').split('=')[-1].split(',')                # get exclude roles(er)
                $ef=($ei -imatch 'exclude_folder').split('=')[-1]                         # get exclude folder path(ef)
                $emrf=($ei -imatch 'exclude_match_role_folder').split('=')[-1].split(',') # get exclude match role folder(emrf)
                $simplify_content=New-Object System.Collections.ArrayList                 # for new csv line save with exclude items removed
                $need_simplify=$false                                                     # flag to tell if report needs to be simplified
                :outerloop                                                                # out loop flag for inner loop break use
                Foreach( $line in $existence_result){                                     # re-read each line of $existence_result
                    If( $line.Role -in $er){$need_simplify=$true;continue}                # go to next loop if it contains exclude role
                    If('Grant' -eq $line.Action){                                         # for newly added items
                        If($line.Folder -imatch "$ef\\?"){$need_simplify=$true;continue}  # go to next loop if it contains exclude folder in new added type
                        Foreach( $r in $emrf){                                            # for each items in the exclude_match_role_folder.txt
                            If($line.Role -imatch "^$r" -and                              # if the role name matched the exclude_role and the folder name
                               $line.Folder -imatch "My \w{4,8}\\$r" )                    # also matched exclude_role like role
                            {$need_simplify=$true;continue outerloop }                    # 'TTS Promoter' contains 'tts' while folder
                        }                                                                 # "My Docs\TTS" also contains 'tts' then go to next loop
                    }                                                                     # otherwise add not matched line
                    $simplify_content.Add($line)|out-null                                 # to the array list for later simplify data report export
                }
                If( $need_simplify ){
                    $simplify_content|Export-Csv "$compare_path\simplify_$old_file_basename-$new_file_basename.csv" -NoTypeInformation -Encoding UTF8 -Force -ea 1
                    Rename-Item -Path $compare_result_csv -NewName "$compare_path\original_$old_file_basename-$new_file_basename.csv" -force -ea 0
                }else{ 
                    $simplify_content.Clear()|out-null  
                    write-log Normal "No exclude item has been found in the compare report, hence no simplify report generated." $log_file
                }
            }else{
                write-log Error "Either exclude_items.txt not exist in $this_path or its content is empty" $log_file
            }
        }
    }else{
        write-log Normal "No difference between 2 csv files`r`n$old_csv`r`n$new_csv" $log_file
    }
    Exit-Script '' $log_file $compare_path  
}
